﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using System.IO;
using System.Text;

namespace DeepSeekTest
{
    internal class Program
    {
        static string tips = "我是 DeepSeek，很高兴见到你！";
        static string name = "DeepSeek";
        static string system = "";

        static async Task Main(string[] args)
        {
            string path = "";
            if (args.Length > 0)
            {
                path = args[0];
            }

            var sys = ReadSystemJson(path);
            if (sys != null)
            {
                tips = sys.tips;
                name = sys.name;
                system = sys.system;
            }

            await HttpCreate();
        }

        private static async Task HttpCreate()
        {
            // 初始化HttpClient
            HttpClient client = CreateClient();
            JObject requestBody = CreateRequestBody();
            JArray messages = ReadChatLog();

            Print(name + ": ", ConsoleColor.Yellow);
            Console.WriteLine(tips);

            while (true)
            {
                Print("我：", ConsoleColor.Green);

                string question = Console.ReadLine() ?? "Hello World";
                if (string.Equals(question, "exit", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }
                else if (string.Equals(question, "new", StringComparison.OrdinalIgnoreCase))
                {
                    messages = NewChat();
                    Print(name + ": ", ConsoleColor.Yellow);
                    Console.WriteLine(tips);
                    continue;
                }

                messages.Add(CreateMessage(question, "user"));

                requestBody["messages"] = messages;
                string msgStr = JsonConvert.SerializeObject(requestBody).ToString();
                StringContent content = new StringContent(msgStr, null, "application/json");

                Console.Write("...");
                var httpreq = new HttpRequestMessage(HttpMethod.Post, "https://api.deepseek.com/chat/completions") { Content = content };
                var response = await client.SendAsync(httpreq, HttpCompletionOption.ResponseHeadersRead);
                //var response = await client.PostAsync("chat/completions", content);
                response.EnsureSuccessStatusCode();
                if (response.IsSuccessStatusCode)
                {
                    var responseStream = await response.Content.ReadAsStreamAsync();
                    using var reader = new StreamReader(responseStream);

                    // 获取当前光标位置
                    int currentCursorLeft = Console.CursorLeft;
                    int currentCursorTop = Console.CursorTop;
                    // 将光标移动到当前行的起始位置
                    Console.SetCursorPosition(0, currentCursorTop);

                    string? line;
                    StringBuilder? assistant = null;
                    Print(name + ": ", ConsoleColor.Yellow);

                    while (!reader.EndOfStream)
                    {
                        line = await reader.ReadLineAsync();
                        if (line == null || line.Contains("[DONE]"))
                        {
                            break;
                        }
                        if (line.Length < 10)
                        {
                            continue;
                        }

                        //获取Json对象
                        line = line.Substring(6);
                        dynamic json = JObject.Parse(line);

                        if (json.choices[0].delta.role != null)
                        {
                            assistant = new StringBuilder();
                        }
                        //获取并输出内容
                        string cnt = json.choices[0].delta.content;
                        assistant?.Append(cnt);
                        Console.Write(cnt);
                        //line = JsonConvert.SerializeObject(json, Formatting.Indented);
                        //Console.WriteLine(line);
                    }
                    if (assistant != null)
                    {
                        messages.Add(CreateMessage(assistant.ToString().Trim('\r', '\n'), "assistant"));
                        SaveChatLog(messages);
                    }
                    Console.Write("\n");
                }
                else
                {
                    Console.WriteLine($"请求失败，状态码: {response.StatusCode}");
                }
            }
        }

        private static HttpClient CreateClient()
        {
            var client = new HttpClient();
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            client.DefaultRequestHeaders.Add("Authorization", "Bearer sk-0beec6bc7df141a1beeba900ecbb5939");
            return client;
        }

        private static JObject CreateRequestBody()
        {
            string jsonStr = @"{
  'model': 'deepseek-chat',
  'frequency_penalty': 0,
  'max_tokens': 2048,
  'presence_penalty': 0,
  'response_format': {
    'type': 'text'
  },
  'stop': null,
  'stream': true,
  'stream_options': null,
  'temperature': 1,
  'top_p': 1,
  'tools': null,
  'tool_choice': 'none',
  'logprobs': false,
  'top_logprobs': null
}";
            return JObject.Parse(jsonStr);
        }

        private static JObject CreateMessage(string content, string role)
        {
            return new JObject
            {
                ["content"] = content,
                ["role"] = role
            };
        }

        static bool HasFieldOrProperty(dynamic obj, string fieldName)
        {
            var type = obj.GetType();
            if (type.GetProperty(fieldName) != null || type.GetField(fieldName) != null)
            {
                return true;
            }
            return false;
        }

        static dynamic? ReadSystemJson(string path)
        {
            string fileName = path;
            if (!File.Exists(fileName))
            {
                return null;
            }
            using var reader = new StreamReader(fileName);
            try
            {
                string buff = reader.ReadToEnd();
                reader.Close();

                return JObject.Parse(buff);
            }
            catch
            {

            }

            return null;
        }

        static void SaveChatLog(JArray messages)
        {
            string jsonStr = messages.ToString(Formatting.Indented);
            string currentDirectory = Environment.CurrentDirectory;
            string fileName = Path.Combine(currentDirectory, "chat.json");
            //Console.WriteLine(fileName);
            //Console.WriteLine(jsonStr);
            using var writer = new StreamWriter(fileName);
            try
            {
                var array = JArray.Parse(jsonStr);
                writer.Write(array.ToString());
                writer.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("保存失败" + ex.Message.ToString());
            }
        }

        static JArray ReadChatLog()
        {
            string currentDirectory = Environment.CurrentDirectory;
            string fileName = Path.Combine(currentDirectory, "chat.json");

            JArray messages = new JArray();
            if (File.Exists(fileName))
            {
                using var reader = new StreamReader(fileName);
                try
                {
                    string buff = reader.ReadToEnd();
                    reader.Close();

                    messages = JArray.Parse(buff);
                    return messages;
                }
                catch
                {

                }
            }

            if (!string.IsNullOrEmpty(system))
            {
                messages.Add(CreateMessage(system, "system"));
            }

            return messages;
        }

        static JArray NewChat()
        {
            JArray messages = new JArray();
            if (!string.IsNullOrEmpty(system))
            {
                messages.Add(CreateMessage(system, "system"));
            }

            return messages;
        }

        static void Print(string msg, ConsoleColor color)
        {
            ConsoleColor originalColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.Write(msg);
            Console.ForegroundColor = originalColor;
        }

        static void PrintLine(string msg, ConsoleColor color)
        {
            ConsoleColor originalColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.WriteLine(msg);
            Console.ForegroundColor = originalColor;
        }
    }
}
